﻿namespace RPCenter.WindowsAPI
{ 
    using System;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Security.Principal;
    using System.Text;

    public class NativeSecurity
    {
        public static void AddUserLogonRight(string Username, string LogonRight)
        {
            AddUserLogonRight(Username, LogonRight, null);
        }

        public static void AddUserLogonRight(string Username, string LogonRight, string MachineName)
        {
            ApiDefinitions.LSA_OBJECT_ATTRIBUTES lsa_object_attributes;
            if (Username.StartsWith(@".\"))
            {
                if (string.IsNullOrEmpty(MachineName))
                {
                    Username = Environment.MachineName + @"\" + Username.Remove(0, 2);
                }
                else
                {
                    Username = MachineName + @"\" + Username.Remove(0, 2);
                }
            }
            NTAccount account = new NTAccount(Username);
            SecurityIdentifier identifier = new SecurityIdentifier(account.Translate(typeof(SecurityIdentifier)).Value);
            byte[] binaryForm = new byte[(identifier.BinaryLength - 1) + 1];
            identifier.GetBinaryForm(binaryForm, 0);
            ApiDefinitions.LSA_UNICODE_STRING systemName = new ApiDefinitions.LSA_UNICODE_STRING();
            if (!string.IsNullOrEmpty(MachineName))
            {
                systemName = ConvertStringToLsaString(MachineName);
            }
            lsa_object_attributes = new ApiDefinitions.LSA_OBJECT_ATTRIBUTES {
                Attributes = 0,
                Length = (uint) Marshal.SizeOf(uint.MaxValue),
                ObjectName = IntPtr.Zero,
                RootDirectory = IntPtr.Zero,
                SecurityDescriptor = IntPtr.Zero,
                SecurityQualityOfService = IntPtr.Zero
            };
            IntPtr zero = IntPtr.Zero;
            try
            {
                uint num2 = ApiDefinitions.LsaNtStatusToWinError(ApiDefinitions.LsaOpenPolicy(ref systemName, ref lsa_object_attributes, ApiDefinitions.LSA_POLICY_ACCESS_MASK.POLICY_LOOKUP_NAMES | ApiDefinitions.LSA_POLICY_ACCESS_MASK.POLICY_CREATE_ACCOUNT, ref zero));
                if (num2 != 0L)
                {
                    throw new ApplicationException("Error opening LSA policy: " + new Win32Exception((int) num2).Message);
                }
                ApiDefinitions.LSA_UNICODE_STRING ref_p = ConvertStringToLsaString(LogonRight);
                uint num = ApiDefinitions.LsaNtStatusToWinError(ApiDefinitions.LsaAddAccountRights(zero, binaryForm, ref ref_p, 1));
                if (num != 0L)
                {
                    throw new ApplicationException("Error adding logon right " + LogonRight + " to user " + Username + " : " + new Win32Exception((int) num).Message);
                }
            }
            finally
            {
                if (!(zero == IntPtr.Zero))
                {
                    ApiDefinitions.LsaClose(zero);
                }
            }
        }

        private static ApiDefinitions.LSA_UNICODE_STRING ConvertStringToLsaString(string OriginalString)
        {
            return new ApiDefinitions.LSA_UNICODE_STRING { Buffer = OriginalString, Length = (ushort) (OriginalString.Length * 2), MaximumLength = (ushort) ((OriginalString.Length * 2) + 1) };
        }

        public static SecurityPrincipalInfo TranslateSidToPrincipal(SecurityIdentifier Sid)
        {
            return TranslateSidToPrincipal(Sid, null);
        }

        public static SecurityPrincipalInfo TranslateSidToPrincipal(SecurityIdentifier Sid, string ComputerName)
        {
            ApiDefinitions.SID_NAME_USE sid_name_use;
            SecurityPrincipalInfo.SidType group;
            if (Sid == null)
            {
                throw new ArgumentException("No SID specified (Sid argument is Nothing)", "Sid");
            }
            byte[] binaryForm = new byte[(Sid.BinaryLength - 1) + 1];
            Sid.GetBinaryForm(binaryForm, 0);
            uint cchName = 0;
            uint cchReferencedDomainName = 0;
            ApiDefinitions.LookupAccountSid(null, binaryForm, null, ref cchName, null, ref cchReferencedDomainName, out sid_name_use);
            if (cchName == 0L)
            {
                if (string.IsNullOrEmpty(ComputerName))
                {
                    throw new Win32Exception();
                }
                ApiDefinitions.LookupAccountSid(ComputerName, binaryForm, null, ref cchName, null, ref cchReferencedDomainName, out sid_name_use);
                if (cchName == 0L)
                {
                    throw new Win32Exception();
                }
            }
            else
            {
                ComputerName = null;
            }
            StringBuilder lpName = new StringBuilder((int) cchName);
            StringBuilder lpReferencedDomainName = new StringBuilder((int) cchReferencedDomainName);
            if (!ApiDefinitions.LookupAccountSid(ComputerName, binaryForm, lpName, ref cchName, lpReferencedDomainName, ref cchReferencedDomainName, out sid_name_use))
            {
                throw new Win32Exception();
            }
            if (((sid_name_use == ApiDefinitions.SID_NAME_USE.SidTypeAlias) || (sid_name_use == ApiDefinitions.SID_NAME_USE.SidTypeGroup)) || (sid_name_use == ApiDefinitions.SID_NAME_USE.SidTypeWellKnownGroup))
            {
                group = SecurityPrincipalInfo.SidType.Group;
            }
            else
            {
                switch (sid_name_use)
                {
                    case ApiDefinitions.SID_NAME_USE.SidTypeComputer:
                        group = SecurityPrincipalInfo.SidType.Computer;
                        goto Label_00D7;

                    case ApiDefinitions.SID_NAME_USE.SidTypeDomain:
                        group = SecurityPrincipalInfo.SidType.Domain;
                        goto Label_00D7;

                    case ApiDefinitions.SID_NAME_USE.SidTypeUser:
                        group = SecurityPrincipalInfo.SidType.User;
                        goto Label_00D7;
                }
                group = SecurityPrincipalInfo.SidType.Other;
            }
        Label_00D7:
            return new SecurityPrincipalInfo(Sid, lpReferencedDomainName.ToString(), lpName.ToString(), group);
        }

        public class SecurityPrincipalInfo
        {
            [CompilerGenerated]
            private string _Domain;
            [CompilerGenerated]
            private string _Name;
            [CompilerGenerated]
            private SecurityIdentifier _Sid;
            [CompilerGenerated]
            private SidType _Type;

            public SecurityPrincipalInfo()
            {
            }

            public SecurityPrincipalInfo(SecurityIdentifier PrincipalSid, string PrincipalDomain, string PrincipalName, SidType PrincipalType)
            {
                this.Sid = PrincipalSid;
                this.Name = PrincipalName;
                this.Domain = PrincipalDomain;
                this.Type = PrincipalType;
            }

            public string DisplayName
            {
                get
                {
                    if (string.IsNullOrEmpty(this.Domain))
                    {
                        return this.Name;
                    }
                    return (this.Domain + @"\" + this.Name);
                }
            }

            public string Domain
            {
                get
                {
                    return this._Domain;
                }
                set
                {
                    this._Domain = value;
                }
            }

            public string Name
            {
                get
                {
                    return this._Name;
                }
                set
                {
                    this._Name = value;
                }
            }

            public SecurityIdentifier Sid
            {
                get
                {
                    return this._Sid;
                }
                set
                {
                    this._Sid = value;
                }
            }

            public SidType Type
            {
                get
                {
                    return this._Type;
                }
                set
                {
                    this._Type = value;
                }
            }

            public enum SidType
            {
                Computer = 2,
                Domain = 4,
                Group = 3,
                Other = 5,
                User = 1
            }
        }
    }
}

